package designpatterns.structure;

import java.util.HashMap;
import java.util.Map;

/**
 * 享元模式
 * 运用共享技术来有効地支持大量细粒度对象的复用。
 * 它通过共享已经存在的又橡来大幅度减少需要创建的对象数量、避免大量相似类的开销，从而提高系统资源的利用率。
 * 使用场景：1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。
 * 4、这些对象可以按照内蕴状态分为很多组，当把外蕴对象从对象中剔除出来时，每一组对象都可以用一个对象来代替。
 * 5、系统不依赖于这些对象身份，这些对象是不可分辨的
 * 优点：大大减少对象的创建，降低系统的内存，使效率提高
 * 缺点：提高了系统的复杂度，需要分离出外部状态和内部状态，而且外部状态具有固有化的性质，
 * 不应该随着内部状态的变化而变化，否则会造成系统的混乱。
 *
 * @author jack.wu
 * @since 2019/9/23
 */
public class FlyweightTest {

    private static final String[] COLOR = {"Red", "Green", "Blue", "White", "Black"};

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            Circle2 circle = ShapeFactory.getCircle(getRandomColor());
            circle.setX(getRandomX());
            circle.setY(getRandomY());
            circle.setRadius(100);
            circle.draw();
        }
    }

    private static int getRandomY() {
        return (int) (Math.random() * 100);
    }

    private static int getRandomX() {
        return (int) (Math.random() * 100);
    }

    private static String getRandomColor() {
        return COLOR[(int) (Math.random() * COLOR.length)];
    }
}

interface Shape2 {
    void draw();
}

class Circle2 implements Shape2 {

    private String color;
    private int x;
    private int y;
    private int radius;

    public Circle2(String color) {
        this.color = color;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Circle: Draw()[Color : " + color +
                ",x : " + x + ",y : " + y + ",radius : " + radius + "]");
    }
}

class ShapeFactory {

    private static final Map<String, Shape2> CIRCLE_MAP = new HashMap<>();

    public static Circle2 getCircle(String color) {
        Circle2 circle = (Circle2) CIRCLE_MAP.get(color);
        if (circle == null) {
            circle = new Circle2(color);
            CIRCLE_MAP.put(color, circle);
            System.out.println("Create Circle of Color :" + color);
        }
        return circle;
    }
}
